package jmine.tec.subscription.replicator;

import java.net.InetAddress;
import java.net.UnknownHostException;

import jmine.tec.subscription.Publication;
import jmine.tec.subscription.Publisher;
import jmine.tec.subscription.PublisherManager;
import jmine.tec.subscription.SubscriptionSettings;
import jmine.tec.subscription.impl.PartialPublication;
import jmine.tec.subscription.impl.SubscriptionManagerImplementor;
import jmine.tec.subscription.replicator.jms.TopicPublicationReplicator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Implementacao esqueleto de {@link PublicationReplicator}. Implementacoes desta classe devem injetar o {@link PublisherManager}
 * 
 * @author takeshi
 */
public abstract class AbstractIdentifiedReplicator implements PublicationReplicator {

    protected static final Log LOGGER = LogFactory.getLog(TopicPublicationReplicator.class);

    private final String identification;

    private SubscriptionManagerImplementor implementor;

    private PublisherManager publisherManager;

    /**
     * C'tor
     */
    public AbstractIdentifiedReplicator() {
        String host = "unknown";
        try {
            host = InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        this.identification = System.identityHashCode(this) + ":" + System.nanoTime() + "@" + host;
        LOGGER.info("Replicator created with UUID: " + this.identification);
    }

    /**
     * Cria um {@link AbstractPublicationWrapper} a partir de um {@link PartialPublication}
     * 
     * @param <P> o tipo da publication
     * @param publisher o {@link Publisher}
     * @param settings os {@link SubscriptionSettings}
     * @param publication a {@link PartialPublication}
     * @return {@link AbstractPublicationWrapper}
     */
    @SuppressWarnings("unchecked")
    protected final <P extends Publication> AbstractPublicationWrapper newPartialPublicationWrapper(Publisher<P> publisher,
            SubscriptionSettings settings, PartialPublication<P> publication) {
        return new PartialPublicationWrapper(settings, publisher.identification(), (PartialPublication<Publication>) publication);
    }

    /**
     * Cria um {@link AbstractPublicationWrapper} a partir de um {@link Publication}
     * 
     * @param <P> o tipo da publication
     * @param publisher o {@link Publisher}
     * @param settings o {@link SubscriptionSettings}
     * @param publication a {@link Publication}
     * @return {@link AbstractPublicationWrapper}
     */
    protected final <P extends Publication> AbstractPublicationWrapper newPublicationWrapper(Publisher<P> publisher,
            SubscriptionSettings settings, P publication) {
        return new PublicationWrapper(settings, publisher.identification(), publication);
    }

    /**
     * Uma string que pode ser usada para identificar esta instancia
     * 
     * @return String
     */
    public final String getIdentification() {
        return this.identification;
    }

    /**
     * {@inheritDoc}
     */
    public final void setSubscriptionManager(SubscriptionManagerImplementor smi) {
        this.implementor = smi;
    }

    /**
     * @param publisherManager the publisherManager to set
     */
    public final void setPublisherManager(PublisherManager publisherManager) {
        this.publisherManager = publisherManager;
    }

    /**
     * Executa o {@link AbstractPublicationWrapper}
     * 
     * @param wrapper {@link AbstractPublicationWrapper}
     */
    protected final void handle(AbstractPublicationWrapper wrapper) {
        wrapper.handleLocally(this.implementor, this.publisherManager);
    }

}
